<?php
App::uses('AppController', 'Controller');
/**
 * SurveyResponses Controller
 *
 * @property SurveyResponse $SurveyResponse
 */
class SurveyResponsesController extends AppController {

	public function beforeFilter() {
	    parent::beforeFilter();
	    $this->Auth->allow('submit', 'thanks'); // Letting users register themselves
	}

	public function summary($surveyId = null) {
		$this->SurveyResponse->Survey->id = $surveyId;
		if (!$this->SurveyResponse->Survey->exists()) {
			throw new NotFoundException("Invalid Survey ID");
		}

		$survey = $this->SurveyResponse->Survey->findById($surveyId);
		$surveyResponses = $this->SurveyResponse->findAllBySurveyId($surveyId);
		$data = array();
		//Header Row
		$headerRow = array();
		foreach ($survey['Question'] as $question) {
			$headerRow[] = $question['label'];
		}
		$data[] = $headerRow;

		//Data
		foreach ($surveyResponses as $surveyResponse) {
			$record = array();
			foreach ($surveyResponse['Response'] as $response) {
				$response = $this->SurveyResponse->Response->findById($response['id']);

				if ($response['ConcreteResponse']) {
					$val = $response['ConcreteResponse']->data[$response['ConcreteResponse']->name]['response_value'];
					$record[] = $val;
				} else {
					$cqrs = $this->SurveyResponse->Response->ChoiceQuestionResponse->findAllByResponseId($response['Response']['id']);
					if (!empty($cqrs)) {
						$picked = array_map(function($a) { return $a['ChoiceQuestionChoice']['label']; }, $cqrs);
						$record[] = $picked;
					} else { 
						$record[] = "-";
					}
				}
				
			}
			$data[] = $record;
		}
		$this->set(compact('data', 'survey'));
	}

	private function stdev($array) {
		//Don Knuth is the $deity of algorithms
		//http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#III._On-line_algorithm
		$n = 0;
		$mean = 0;
		$M2 = 0;
		foreach($array as $x){
			$n++;
			$delta = $x - $mean;
			$mean = $mean + $delta/$n;
			$M2 = $M2 + $delta*($x - $mean);
		}
		$variance = $M2/($n - 1);
		return sqrt($variance);
	}

	public function analytics($surveyId) {
		$this->SurveyResponse->Survey->id = $surveyId;
		if (!$this->SurveyResponse->Survey->exists()) {
			throw new NotFoundException("Invalid Survey ID");
		}

		$survey = $this->SurveyResponse->Survey->findById($surveyId);
		$questions = $this->SurveyResponse->Survey->Question->findAllBySurveyId($survey['Survey']['id']);
		$summaryData = array();

		foreach ($questions as $q) {
			$responses = $this->SurveyResponse->Response->findAllByQuestionId($q['Question']['id']);
			$sdRow = array(
				'type' => $q['ConcreteQuestion']->name,
				'cq' => $q['ConcreteQuestion']->data,
			);
			switch ($q['ConcreteQuestion']->name) {
				case  'TextQuestion':
					// Count number of responses
					$rSet = array();
					foreach ($responses as $resp) {
						$cr = $resp['ConcreteResponse']->data['TextResponse']['response_value'];
						//TODO: fuzzy string matching
						if (!in_array($cr, array_keys($rSet))) {
							$rSet[$cr] = 0;
						}

						$rSet[$cr] += 1;
					}

					arsort($rSet);
					$sdRow['data'] = $rSet;
					break;
				case 'ChoiceQuestion':
					$pickSet = array();

					foreach ($q['ConcreteQuestion']->data['ChoiceQuestionChoice'] as $choice) {
						$pickSet[$choice['label']] = 0;
					}

					foreach ($responses as $resp) {
						$cqr = $this->SurveyResponse->Response->ChoiceQuestionResponse->findAllByResponseId($resp['Response']['id']);
						$picks = array_map(function($c) { return $c['ChoiceQuestionChoice']['label']; }, $cqr);

						foreach ($picks as $pick) {
							if (!in_array($pick, array_keys($pickSet))) {
								$pickSet[$pick] = 0;
							}

							$pickSet[$pick] += 1;
						}
					}

					$sdRow['data'] = $pickSet;
					break;
				case 'ScaledQuestion':
					$max = ~PHP_INT_MAX;
					$min = PHP_INT_MAX;
					$sum = 0;
					$count = count($responses);

					foreach ($responses as $resp) {
						$cr = $resp['ConcreteResponse']->data['NumericResponse']['response_value'];
						$crNum = intval($cr);
						$min = min($min, $crNum);
						$max = max($max, $crNum);
						$sum += $crNum;
					}

					$avg = (float)$sum / (float)$count;
					$stdev = $this->stdev(array_map(function($r) { return $r['ConcreteResponse']->data['NumericResponse']['response_value']; }, $responses));

					$sdRow['data'] = compact('min', 'max', 'sum', 'avg', 'count', 'stdev');

					break;
				default:
					throw new InvalidArgumentException("Unhandled ConcreteQuestion type");
					break;
			} 
			$summaryData[] = $sdRow;
		}

		$this->set(compact('summaryData', 'survey'));
	}

	public function thanks() {

	}

	public function submit($identifier = null) {
		$survey = $this->SurveyResponse->Survey->findByIdentifier($identifier);

		if ($this->request->is('post') or $this->request->is('put')) {
			Debugger::dump($this->request->data);
			$dataToSave = array(
				'SurveyResponse' => array(
					'survey_id' => $survey['Survey']['id'],
					'ip_address' => $this->request->clientIp(),
				),
				'Response' => array(),
			);
			foreach ($this->request->data as $qname => $qval) {
				list($questionId) = sscanf($qname, "Question-%d");
				$question = $this->SurveyResponse->Survey->Question->findById($questionId);
				$newResponse = array('question_id' => $question['Question']['id']);

				switch ($question['ConcreteQuestion']->name) {
					case "TextQuestion":
						$newResponse['TextResponse'] = array('response_value' => $qval);
						break;
					case "ScaledQuestion":
						$newResponse['NumericResponse'] = array('response_value' => $qval);
						break;
					case "ChoiceQuestion":
						$cqrs = array();
						if (!is_array($qval)) {
							$qval = array($qval);
						}
						foreach ($qval as $choiceId) {
							$cqrs[] = array(
								'choicequestionchoice_id' => $choiceId,
							);
						}
						$newResponse['ChoiceQuestionResponse'] = $cqrs;
						break;
					default:
						throw new NotFoundException("Invalid Question Type");
				}

				$dataToSave['Response'][] = $newResponse;
			}
			echo "<pre>";
			print_r($dataToSave);
			echo "</pre>";

			if ($this->SurveyResponse->saveAssociated($dataToSave, array('deep' => true))) {
				$this->redirect(array('action' => 'thanks'));
			}
		}

		$survey['Question'] = $this->SurveyResponse->Survey->Question->findAllBySurveyId($survey['Survey']['id'], array(), array('Question.numeral' => 'asc'));

		if (!$survey) {
			throw new NotFoundException("Invalid Survey Identifier");
		}

		$this->set(compact('survey'));
	}
}
